<template>
  <!--
    要么不传filterMode，其它页面
    录像管理传，必须是ipcMode显示且是普通ipc

    v-if="
      (!filterMode || 
        (filterMode === 'ipcMode' && ipcType === 'normal')
      ) && 
      (treeData && treeData.children &&treeData.children.length > 0 || 
       treeData && treeData.ipc_list && treeData.ipc_list.length > 0
      )
    "
   -->
  <div 
    class="viewport"
    ref="viewport"
    @scroll="handleScroll"
    v-if="showVirtualList"
    >
    <!-- 占位容器 -->
    <div class="placeholder"
    :style="{height: contentHeight}"
    ></div>
    <!-- 内容区域 -->
    <ul class="sb-tree"
     :style="{transform: `translateY(${offset}px)`}"
    >
      <!-- 
        item.id是目录
        item.path + item.uuid是ip的防止重复，一个ip可能在多个目录下
      -->
      <li 
        v-for="item in visibleData" 
        :key="treeId(item)"
      >
        <!-- ipc -->
        <span
          v-if="item.ip"
          :title="!item.name ? item.uuid : ''"
          @click.prevent.stop="handleNodeClick(item)"
          class="tree-item"
          :style="{
            display: 'block',
            background: (item.path + item.uuid) === ($store.state.selectCatalog.path + $store.state.selectCatalog.id) ? '#F1F4FF' : 'none',
            color: (item.path + item.uuid) === ($store.state.selectCatalog.path + $store.state.selectCatalog.id) ? '#3C7EFF' : '#2C3E50',
            paddingLeft: 12.5 * (item.level - 1) + 'px',
          }"
        >
          <!-- IPC节点 -->
          <span 
          @click.prevent.stop="handleNodeClick(item)"
          class="tree-item-content"
          >
            <!-- IPC图标 -->
            <i
              class="el-icon-my-catalog-hdhalfdome"
              v-if="item.appearance === 'HD Half-Dome'"
              @click.prevent.stop="handleNodeClick(item, 'icon')"
              style="margin: 0px 6px 0px 0px;"
            ></i>
            <i
              class="el-icon-my-catalog-hddome"
              v-else-if="item.appearance === 'HD Dome'"
              @click.prevent.stop="handleNodeClick(item, 'icon')"
              style="margin: 0px 6px 0px 0px;"
            ></i>
            <i
              class="el-icon-my-catalog-controllable"
              v-else-if="item.appearance === 'Controllable Ipc'"
              @click.prevent.stop="handleNodeClick(item, 'icon')"
              style="margin: 0px 6px 0px 0px;"
            ></i>
            <i
              class="el-icon-my-catalog-hdbullet"
              v-else
              @click.prevent.stop="handleNodeClick(item, 'icon')"
              style="margin: 0px 6px 0px 0px;"
            ></i>
            <!-- 常规ipc或者目录 -->
            <span v-if="item.name" class="text-hover">
              {{ item["name"] ? item["name"] : item["ip"] }}
            </span>
            <!-- 特殊IPC名称 -->
            <span v-else class="text-hover">
              {{ item["uuid"] ? item["uuid"] : item["ip"] }}
            </span>
            <!-- 提示：录像管理 -->
            <!-- 得加data.ip做判断，不然可能会出现鼠标经过tooltip但是没有内容的情况 -->
            <el-tooltip placement="right-end" popper-class="ipPopper">
              <div class="ipc-item" slot="content">
                <div>
                    <span class="label">{{$t('ipcList.IPC IP')}}</span>
                    <span class="content">{{item.ip}}</span>
                </div>
                <div>
                    <span class="label">{{$t('ipcList.IPC name')}}</span>
                    <span class="content" :title="item.name">{{item.name}}</span>
                </div>
                <div>
                    <span class="label">{{$t('ipcList.IPC UUID')}}</span>
                    <span class="content" :title="item.name">{{item.uuid}}</span>
                </div>
                <div>
                    <span class="label">{{$t('ipcList.Record Days')}}</span>
                    <span class="content">{{item.recordExpiry}}</span>
                </div>
              </div>
              <i class="el-icon-my-catalog-ipc-end" v-if="filterType !== 'special'"></i>
            </el-tooltip>
          </span>
        </span>
        <!-- 目录 -->
        <span
        v-else
        :title="`${item['name']}`"
        @click.prevent.stop="handleNodeClick(item)"
        class="tree-item"
        :style="{
          background: item.id === $store.state.selectCatalog.id ? '#f1f4ff' : 'none',
          color: item.id === $store.state.selectCatalog.id ? '#3C7EFF' : '#2C3E50',
          paddingLeft: 8 * (item.level - 1) + 'px'
        }"
      >
      <!--
          :draggable="situation === 'catalog' && item.path !== $t('ipcList.rootCompare') && item.path !== $t('ipcList.default catalog')"  
          @dragstart="startDrag($event, item)"
          @drop="onDrop($event, item)"
          @dragover.prevent="onDragOver($event, item)"
          @dragenter.prevent 
      -->
          <span
            class="tree-item-content"
            @click.prevent.stop="handleNodeClick(item)"
            @mousedown.prevent.stop="onMousedown($event, item)"
            @dragover.prevent>
              <!-- 展开箭头图标 -->
              <i
                v-if="item.showChildren"
                class="el-icon-caret-bottom"
                @click.prevent.stop="handleNodeClick(item)"
                :style="{visibility: showTreeCater(item) ? 'visible' : 'hidden'}"
              ></i>
              <!-- 折叠箭头图标 -->
              <i
                v-else
                class="el-icon-caret-right"
                @click.prevent.stop="handleNodeClick(item)"
                :style="{visibility: showTreeCater(item) ? 'visible' : 'hidden'}"
              ></i>
              <!-- 图标：默认目录 -->
              <i
                style="margin: 0px 6px 0px 3px;"
                class="el-icon-loading"
                v-if="item.loading"
              ></i>
              <i
                style="margin: 0px 6px 0px 3px;"
                class="el-icon-my-catalog-default"
                v-else-if="item.name === $t('ipcList.default catalog compare')"
              ></i>
              <!-- 组织图标 -->
              <i
                style="margin: 0px 6px 0px 3px;"
                class="el-icon-my-catalog-folder"
                v-else
                @click.prevent.stop="handleNodeClick(item)"
              ></i>

            <!-- 组织名称 -->
            <span class="text-hover" :attrs-path="item.path">{{ item["name"] }} </span>
            <!-- 提示：默认目录 -->
            <el-tooltip  effect="dark" v-if="item.name && item.name === $t('ipcList.default catalog compare')">
              <div slot="content">
                <p>{{ $t('ipcList.default catalog desc')}}</p>
              </div>
              <i class="el-icon-question ipc_remove_tips"></i>
            </el-tooltip>
              <!-- 默认目录下，既不能重命名 新增 删除 -->
              <span>
                <el-dropdown v-if="$route.path === '/config/catalog' && item.name !== $t('ipcList.default catalog compare')">
                <span class="el-dropdown-link">
                  <i
                    class="el-icon-my-catalog-more"
                    slot="reference"
                    @click.stop=""
                  ></i>
                </span>
                <el-dropdown-menu slot="dropdown">
                  <el-dropdown-item
                    @click.native="modifyCatalog(item)"
                    v-if="
                      item.name !== $t('ipcList.root') &&
                      item.name !== $t('ipcList.default catalog compare')
                    "
                  >
                    <span>{{ $t("common.rename") }}</span>
                  </el-dropdown-item>
                  <el-dropdown-item @click.native="addCatalog(item)">
                    <span>{{ $t("common.add") }}</span>
                  </el-dropdown-item>
                  <el-dropdown-item
                    @click.native="deleteCatalog(item)"
                    v-if="
                      item.name !== $t('ipcList.root') &&
                      item.name !== $t('ipcList.default catalog compare')
                    "
                  >
                    <span>{{ $t("common.delete") }}</span>
                  </el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
              </span>
              <!-- ({{ item["ipc_list"].length }}) -->
          </span>
        </span>
      </li>
    </ul>
  </div>
  <!-- 录像管理 特殊ipc模式 - 文件存储  -->
  <div v-else-if="filterMode === 'ipcMode' && ipcType === 'special'">
    <div
        v-for="item in tableData"
        :key="item.uuid + item.ip"
        class="fileStore ipc-item"
        @click="selectIpcItem(item)"
        :class="{ hoverEd:(item.ip === clickRow.ip && item.uuid === clickRow.uuid)}"
        :style="{
           'background': item.ip === clickRow.ip && item.uuid === clickRow.uuid ? '#f4f7ff' : ''
        }"
    >
        <div> 
            <span>{{ $t('ipcList.IPC IP') }}</span>
            <span>{{item.ip}}</span>
        </div>
        <div v-show="ipcType === 'normal'">
            <span>{{ $t('ipcList.IPC name') }}</span>
            <span>{{item.name}}</span>
        </div>
        <div>
            <span>{{ $t('ipcList.IPC UUID') }}</span>
            <span>{{item.uuid}}</span>
        </div>
        <div>
            <span>{{ $t('ipcList.Record Days') }}</span>
            <span>{{item.recordExpiry}}</span>
        </div>
    </div>
    <div v-if="tableData && tableData.length<1">
        <el-table
            :data="[]"
            :cell-style="{ padding: '0px' }"
            :row-style="{ height: '35px' }"
            style="padding:150px 0"
            :class="$i18n.locale"
            class="ipcSpecialTable"
        >
            <template slot="empty">
                <div class="flex-empty">
                    <img :src="require('@/assets/empty-image.png')" alt="" srcset="" />
                    <div>{{ $t('ipcList.no Ipc') }}</div>
                </div>             
            </template>
        </el-table>
    </div>
  </div>
  <!-- 录像管理 节点模式 - 文件存储  -->
  <div v-else-if="filterMode === 'nodeMode' && !$store.state.isStorageTypeObject">
      <div
          v-for="item in tableData"
          :key="item.uuid + item.ip"
          class="fileStore ipc-item"
          @click="selectIpcItem(item)"
          :class="{ hoverEd:(item.ip === clickRow.ip && item.uuid === clickRow.uuid)}"
          :style="{
           'background': item.ip === clickRow.ip && item.uuid === clickRow.uuid ? '#f4f7ff' : ''
          }"
      >
          <div>
              <span>{{$t('ipcList.node IP')}}</span>
              <span>{{item.ip}}</span>
          </div>

          <div>
              <span>{{$t('ipcList.node UUID')}}</span>
              <span>{{item.uuid}}</span>
          </div>
          <!-- <div>
              <span>{{$t('ipcList.node with cameras IPC num')}}</span>
              <span>{{item.ipcNum}}</span>
          </div> -->
      </div>
      <div v-if="tableData && tableData.length<1">
          <el-table
              :data="[]"
              :cell-style="{ padding: '0px' }"
              :row-style="{ height: '35px' }"
              style="padding:150px 0"
          >
              <template slot="empty" >
                  <div class="flex-empty">
                      <img :src="require('@/assets/empty-image.png')" alt="" srcset="" />
                      <div>{{$t('ipcList.no node')}}</div>
                  </div>    
              </template>
          </el-table>
      </div>
  </div>
  <!-- 对象存储 节点模式 -->
  <div v-else-if="filterMode === 'nodeMode' && $store.state.isStorageTypeObject">
    <el-table
        :data="[]"
        :cell-style="{ padding: '0px' }"
        :row-style="{ height: '35px' }"
        style="padding:200px 0"
        class="nodeTable"
        :class="$i18n.locale"
    >
        <template slot="empty" >
            <div class="flex-empty">
                <img :src="require('@/assets/empty-image.png')" alt="" srcset="" />
                <div>{{$t('ipcList.all Nodes Share the storagePool')}}</div>
            </div>    
        </template>
    </el-table>
  </div>

  <div
    v-else
    style="height: 100%;"
  >
    <el-table :empty-text="$t('ipcList.no Ipc And Catalog')"></el-table>
  </div>
</template>

<script>
import {
  modifyIpcCataLog,
  addCfgCataLogIpc,
  modCfgCataLog
} from "@/api/catalog";
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import {
  insertSorted,
  sortIpcList
} from '@/utils/common'
import {
  deepCopy
} from '@/utils'
import bus from '@/utils/bus'
let lastTime = 0
export default {
  name: "RecurseVirtualTree",
  inject: ['getCurDragObj'],
  props: {
    filterMode: {
      type: String,
    },
    // 组织树数据
    treeData: {
      type: Object,
      default: () => {},
    },
    // 录像-特殊ipc数据
    specialList: {
      type: Array,
      default: () => [],
    },
    situation: {
      type: String,
      default: "catalog", // 默认目录管理
    },
    filterType: {
      type: String,
      default: "IpcName",
    },
    // 录像管理-特殊ipc/节点模式数据
    tableData: {
      type: Array,
      default: () => [],
    },
    clickRow: {
      type: Object,
      default: () => {},
    },
    // 特殊ipc还是普通ipc呢？
    ipcType: {
      type: String,
    },
    ipcList: {
      type: Array,
      default: () => []
    },
    option: {
      type: Object,
      default: () => {}
    },
    isFilter: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      treeClickCount: 0,
      clickTimer: undefined,
      dragObj: undefined,
      selectedNode: this.$store.state.selectCatalog.id, // 选中节点的id（目录）或者uuid（ipc）
      selectPath: this.$store.state.selectCatalog.path || "", // 选中节点的路径
      isControl: false, // 是否按下ctrl键(ipc拖动到目录复制用)
      // loading: false, // 加载中
      isMouseDown: false, // 是否是mousedown
      isMouseMove: false, // 是否是mousedown
      offset: 0,
      start: 0, // 数据开始索引
      end: 0,
      treeObj: {}, // 树数据
      specialData: [], // 特殊ipc数据
      visibleData: [], // 可视区域的数据
      allVisibleData: [], // 所有可以显示的数据
      flattenTree: [], // treeData拍平后的所有数据
      contentHeight: [], // 占位容器布局高度
      top: 0, // 滚动的距离
      clientX: 0, // 鼠标点击的坐标x
      clientY: 0, // 鼠标点击的坐标y
      catalogText: this.$t('ipcList.move Catalog'),
      firstLoadTree: true, // 第一次加载树
      mode: undefined // 录像管理跳转过来的模式
    };
  },
  created() {
    this.firstLoad()
    this.pushShiftOrControl()
  },
  mounted() {
    if (this.$route.query &&  this.$route.query.filterType !== 'special' && this.$route.query.filterMode !== 'nodeMode') {
      this.updateView()
    }
  },
  beforeDestroy() {
    clearTimeout(this.clickTimer);
    let storeTreePath = [
      '/config/ipcManagement/ipcConfig',
      '/config/ipcManagement/ipcStatistics',
      '/record',
      '/config/recordManagement'
    ]
    // 排除离开ipc管理渠道ipc的配置和统计，
    if (!(storeTreePath.includes(this.$route.path) && this.$store.state.treeJumpData)) {
      // 设置选中的节点为根目录
      this.$store.commit('setSelectCatalog', {path: this.$t('ipcList.rootCompare'), id: 0})
    }
  },
  computed: {
    curDragObjItem () {
      return this.getCurDragObj()
    },
    allVisibleDataLength () {
      return this.allVisibleData.length
    },
    ipcConfig () {
      return this.situation === 'ipcMgt' && this.$route.query && JSON.stringify(this.$route.query) !== '{}'
    },
    recordMgtDetail () {
      return (this.situation === 'recordMgt' || this.situation === 'record') && this.$store.state.treeJumpData 
    },
    showVirtualList() {
      return (
        (
          // 如果没有传递filterMode，就是除了录像管理的页面
          // 传递了filterMode，ipcType是normal，是录像管理的常规IPC
          (
          !this.filterMode || 
          (this.filterMode === 'ipcMode' && this.ipcType === 'normal')
          ) 
          && 
          (
            // this.treeData.children是目录有数据
            // this.treeData.ipc_list是ipc列表有数据
            (this.treeData && this.treeData.children && this.treeData.children.length > 0) || 
            (this.treeData && this.treeData.ipc_list && this.treeData.ipc_list.length) > 0
          )
        )
        ||
        // 录像页面展示特殊ipc
        (
          (
            this.filterType === 'special' ||
            this.mode === 'nodeMode'
          )
          &&
          this.specialList.length > 0
        )
      )
    },
    isCatalogOrIpcMgt() {
      return this.situation === 'catalog' || this.situation === 'ipcMgt'
    }
  },
  watch: {
    // 监听tableData
    tableData (val) {
      // 对象存储模式刚进入默认点击其中第一个数据
      if (this.filterMode === "nodeMode" && this.$store.state.isStorageTypeObject) {
        if (this.tableData && this.tableData.length > 0) {
            this.$emit("changeSelectIp", this.tableData[0].ip, this.tableData[0].uuid)
            this.selectIpcItem(this.tableData[0]) 
        } else {
            this.$message({
                showClose: true,
                message: this.$t('ipcList.cant search the Ipc Information'),
                type: "error",
            });
        }
      }
    },
    allVisibleDataLength: {
      handler (newVal, oldVal) {
        if (newVal !== oldVal) {
          // 展开节点比如ipc多了 -> 可以显示的数组长度变化 -> 更新展位容器的高度，滚动条显示正常
          this.updatePlaceHolderHeight()
        }
      },
      deep: true
    },
    treeData: {
      immediate: true,
      handler(newVal, oldVal) {
        // 这儿只有初始化执行，节点操作和搜索如果触发会造成栈溢出；搜索手动调用updateFlatten；节点操作，父子组件的数据分开修改
        if (newVal.children && newVal.children.length > 0 && (this.firstLoadTree)) {
          this.updateFlatten(newVal)
          if (this.firstLoadTree) this.firstLoadTree = false // 后续加载树手动更新，这个必须得放这儿，有时候treeData的children加载不及时
        }
      },
      deep: true,
    },
    specialList: {
      immediate: true,
      handler(newVal, oldVal) {
        if (newVal) {
          // 这里先于created执行，防止viewport不存在，先赋值；mode为nodeMode的时候，specialList有值时viewport也可以显示
          this.mode = this.$route.query.filterMode
          this.updateFlatten(newVal)
          this.$nextTick(() => {
            this.updateView()
          })
        }
      },
      deep: true,
    }
  },
  methods: {
    // 展示树的折叠和展开按钮
    showTreeCater(item) {
      // 目录管理或者ipc管理
      if (this.isCatalogOrIpcMgt) {
        if (item.children && item.children.length > 0) return true
        else return false
      } else {
        // 其他页面，有ipc或者有子目录展示折叠按钮
        if (
          (item.children && item.children.length > 0) ||
          (item.ipc_list && item.ipc_list.length > 0)
        ) {
          return true
        }
        else {
          return false
        }
      }
    },
    treeId(item) {
      return item.id || (item.path + item.uuid + Math.random(0, 100) * 100)
    },
    /* 区分更新flattenTree数组 */
    updateFlatten (newVal) {
      try {
        if (
          newVal && Array.isArray(newVal) &&
          (
            (this.filterType === 'special') ||
            (this.$route.query.filterMode === 'nodeMode')
          )
        ) {
          // 录像管理跳录像 特殊ipc，只显示选中的ipc，newVal只有一个
          this.specialData = deepCopy(newVal)
          this.initFlatten(null, this.specialData);
          // 更新选中节点
          if (this.recordMgtDetail) {
            // 跳转的一瞬间
            if (this.specialData.length > 0) {
              this.$store.commit('setSelectCatalog', {path: this.specialData[0].uuid, id: this.specialData[0].uuid})
            }
          }
        }
        else if (newVal && newVal.children && Array.isArray(newVal.children)) {
          if (this.recordMgtDetail) {
            // 录像管理跳录像，常规ipc
            this.treeObj = this.$store.state.treeJumpData.treeObj
          } 
          else if (this.ipcConfig) {
            // 常规IPC
            this.treeObj = this.$store.state.treeJumpData.treeObj
          }
          else  {
            // 所有的其他情况
            this.treeObj = deepCopy(newVal);
          }
          this.initFlatten(null, this.treeObj.children);
        } 
      } catch (error) {
        console.log(error, 'error')
      }
    },
    refreshCatalogIpc (orgList, ipcList) {
      try {
        // 更新选中目录
        if (
          this.$store.state.selectCatalog && 
          (this.$store.state.selectCatalog.data && 
          !this.$store.state.selectCatalog.data.ip)
        ) {
          let newCatalog = orgList.find(item => item.name === this.$store.state.selectCatalog.path)
          if (newCatalog) {
            // 目录还在
            const { element, parent } = this.getChildAndParentTree(this.treeObj.children, this.$store.state.selectCatalog.path)
            let newIpcList = []
            for (let key in newCatalog.ipc_list) {
              // 更新目录下面的所有ipc
              let ip = ipcList.find(ip => ip.uuid === key)
              if (ip) {
                this.$set(ip, 'visible', element.showChildren)
                this.$set(ip, 'level', element.level + 1)
                let oldIpc = element.ipc_list.find(item => item.uuid === key)
                this.$set(ip, 'path', oldIpc.path)
                newIpcList.push(ip)
              }
            }
            // 删掉该目录下所有的ipc，然后再一个个push进去
            element.ipc_list.splice(0)
            sortIpcList(newIpcList, 'name').forEach((ipc, index) => {
              // if (index > 2) {
              //   return
              // } // 用于测试
              element.ipc_list.push(ipc)
              // this.$set(element, 'ipc_list', index, ipc) // 这个不成,注意测试响应式是否保留
            })
            // 重新更新视图
            this.initFlatten()
            this.updateVisibleData()
            if (element.path === this.$t('ipcList.rootCompare')) {
              this.$emit('selectIpc', 'catalog', element, this.ipcList) // 点击ipc组织树
            } else {
              this.$emit('selectIpc', 'catalog', element) // 点击ipc组织树
            }
          } else {
            // 如果更新后这个目录不在了，要找到这个目录的parent，删掉这个目录
          }
        } else if (this.$store.state.selectCatalog && this.$store.state.selectCatalog.data && this.$store.state.selectCatalog.data.ip) {
          // 更新选中的IPC
          // 找到ipc的父亲
          let arr = this.$store.state.selectCatalog.path.split('/')
          let str = arr.slice(0, arr.length - 1).join('/')
          const { element, parent } = this.getChildAndParentTree(this.treeObj.children, str)
          // ipc在目录中的索引
          let index = element.ipc_list &&  element.ipc_list.findIndex(item => item.uuid === this.$store.state.selectCatalog.id)
          let newCatalog = orgList.find(item => item.name === element.path)
          let newIpc;
          if (newCatalog) {
            for (let key in newCatalog.ipc_list) {
              // 新目录有指定ipc
              if (key === this.$store.state.selectCatalog.id) {
                // 最新的ipc数据newIpc
                newIpc = ipcList.find(item => item.uuid === this.$store.state.selectCatalog.id)
                this.$set(newIpc, 'visible', element.showChildren)
                this.$set(newIpc, 'level', element.level + 1)
                // 更新ipc的path
                this.$set(newIpc, 'path', this.$store.state.selectCatalog.path)
              }
            }
            if (newIpc) {
              // 删掉旧的
              element.ipc_list.splice(index, 1)
              element.ipc_list.splice(index, 0, newIpc)
              // 重新更新视图
              this.initFlatten()
              this.updateVisibleData()
              // 点击右侧表格更新
              this.$emit('selectIpc', 'ipc', newIpc) 
            } else {
              // 新目录里面没有该ipc
            }
          }
        }
      } catch (error) {
        console.log(error, 'error');
      }
    },
    setJumpData (filterValue, filterType, other = {}) {
      // 恢复跳转，要记录treeData,开始索引，结束索引，滚动高度，用旧的tree弄出开始索引和结束索引，设置滚动高度就可以恢复之前的选中情况
      this.$store.commit('setTreeJumpData', {
        start: this.start,
        end: this.end,
        treeData: this.treeData,
        treeObj: this.treeObj,
        top: this.top,
        filterValue: filterValue,
        filterType: filterType,
        otherData: {
          ipcType: other.ipcType,// 判断是否是特殊ipc
          selectUuid: other.selectUuid, // 记录特殊IPC的uuid
          filterMode: other.filterMode
        } 
      })
    },
    // 初始化拍平的数组
    initFlatten (isSearch, arr) {
      // 没有传递arr时 用treeObj
      if (
        (arr && arr.length === 0 && this.filterType !== 'special') || 
        !arr
      ) {
        arr = this.treeObj.children
      }
      this.flattenTree = this.flatten (arr, 'children', 1, {
        level: 0,
        showChildren: true,
        expand: true,
        children: arr
      }, undefined, isSearch)
      this.updatePlaceHolderHeight()
    },
    // 拍平数组
    flatten (
      list = [],
      childKey = 'children',
      level = 1,
      parent = null,
      defaultExpand = true,
      isSearch
        ) {
        if (!Array.isArray(list)) {
          return
        }
        let arr = []
          // 无ipc
        list.forEach((item) => {
          this.$set(item, 'level', level)
          if (item.showChildren === undefined) {
            item.showChildren === defaultExpand
            this.$set(item, 'showChildren', defaultExpand)
          }
          if (item.visible === undefined && level > 2) {
            this.$set(item, 'visible', false)
          } else if (item.visible === undefined) {
            this.$set(item, 'visible', true)
          }
          // if (!parent.visible || !parent.expand) {
          //   item.visible = false
          // }
          this.$set(item, 'parent', parent)
          // 当前目录
          arr.push(item)
          if (this.situation !== 'catalog' && this.situation !== 'ipcMgt') {
            // 当前目录下的ipc
            if (item.ipc_list && item.ipc_list.length > 0) {
              if (isSearch) {
                // 搜索，目录下ipc要展开
                item.ipc_list.forEach(ipc => {
                  this.$set(ipc, 'visible', true)
                  this.$set(ipc, 'level', level + 1)
                  arr.push(ipc)
                })
              } else {          
                // 不是搜索，不展开    
                item.ipc_list.forEach(ipc => {
                  // 根据父亲的展示与否设置ipc的显示
                  this.$set(ipc, 'visible', item.showChildren)
                  this.$set(ipc, 'level', level + 1)
                  arr.push(ipc)
                })
              }
            }
          }
          // 当前目录下的子目录
          if (item[childKey] && item[childKey].length > 0) {
            arr.push(...this.flatten(
              item[childKey],
              childKey,
              level + 1,
              item,
              defaultExpand,
              isSearch
            ))
          }
        })
        return arr
    },
    // 更新展位容器高度
    updatePlaceHolderHeight() {
      this.contentHeight = (this.flattenTree || []).filter(item => item.visible).length * this.option.itemHeight + 'px'
    },
    // 更新视图
    updateView () {
      if (!this.ipcConfig && !this.recordMgtDetail) {
        this.handleScroll()
      } else {
        // 首次加载
        this.start = this.$store.state.treeJumpData.start
        this.end = this.$store.state.treeJumpData.end
        // 所有显示数组
        this.allVisibleData = (this.flattenTree || []).filter(item => item.visible)
        // 渲染的数据
        if (
          (this.$route.query.filterType === 'special' && this.situation === 'record') || 
          this.$route.query.filterMode === 'nodeMode'
        ) {
          this.visibleData = this.allVisibleData
        } else {
          this.visibleData = this.allVisibleData.slice(this.start, this.end)
        }
        this.$refs.viewport.scrollTop = this.$store.state.treeJumpData.top === 0 ? 1 : this.$store.state.treeJumpData.top
        this.offset = this.start * this.option.itemHeight
        if (this.ipcConfig) {
          this.$parent.$parent.setSearchValue(this.$store.state.treeJumpData.searchValue)
        }
        this.$store.commit('setTreeJumpData', null) 
        this.$router.push({ query: {} })
      }
    },
    handleScroll () {
      let currentTime = +new Date()
      if (this.$refs.viewport && (currentTime - lastTime) > this.option.timeout) {
        this.top = this.$refs.viewport.scrollTop // 滚动的距离
        this.updateVisibleData(this.top)
        lastTime = currentTime
      }
    },
    // 更新可视区域的数据
    updateVisibleData (scrollValue = 0) {
      // 计算开始和结束索引
      this.start = Math.floor(scrollValue / this.option.itemHeight) - Math.floor(this.option.count / 2) // 防止白屏多减去 Math.floor(this.option.count / 2)
      this.start = this.start < 0 ? 0 : this.start
      this.end = this.start + this.option.count * 2
      // 所有显示数组
      this.allVisibleData = (this.flattenTree || []).filter(item => item.visible)
      // 渲染的数据
      this.visibleData = this.allVisibleData.slice(this.start, this.end)
      this.offset = this.start * this.option.itemHeight
    },
    // 首次加载
    firstLoad () {
      // this.initFlatten()
      // ipc管理，从配置或者统计返回
      if (this.situation === 'ipcMgt' && this.ipcConfig) {
        this.selectPath = this.$store.state.selectCatalog.path
        this.selectedNode = this.$store.state.selectCatalog.id
        this.$emit("updateIpcList", {path: this.selectPath});
      }

      // 目录管理和ipc管理首次加载
      else if (this.situation === 'catalog' || this.situation === 'ipcMgt') { 
        this.$emit("updateIpcList", {path: this.selectPath});
      } 

      else if (this.situation === 'recordMgt' && this.recordMgtDetail) {
        // 录像管理 —> 详情 -> 录像 -> 返回录像管理
        this.selectPath = this.$store.state.selectCatalog.path
        this.selectedNode = this.$store.state.selectCatalog.id
        if (this.$store.state.selectCatalog.data && this.$store.state.selectCatalog.data.ip) {
          this.$emit('showDataBase', this.$store.state.selectCatalog.data) // 热力图展示
          this.$emit('changeSelectIp', this.$store.state.selectCatalog.data.ip) // 选中的ip，给到热力图和数据图
        }
      }

      else if (this.situation === 'record' && this.recordMgtDetail) {
        this.selectPath = this.$store.state.selectCatalog.path
        this.selectedNode = this.$store.state.selectCatalog.id
        if (this.$store.state.selectCatalog.data && this.$store.state.selectCatalog.data.ip) {
          this.$emit('selectIpc', this.$store.state.selectCatalog.data) // 点击ipc组织树
        }
      }

      else if (this.situation === 'live') {
        this.selectPath = this.$store.state.selectCatalog.path
        this.selectedNode = this.$store.state.selectCatalog.id
        if (this.$store.state.selectCatalog.path === this.$t('ipcList.rootCompare')) {
          this.$emit('selectIpc', 'catalog', this.$store.state.selectCatalog, this.ipcList) // 点击ipc组织树
        } else {
          this.$emit('selectIpc', 'catalog', this.$store.state.selectCatalog) // 点击ipc组织树
        }
      }
    },
    // 判断是否按下了shift或者control键
    pushShiftOrControl() {
      document.addEventListener('keydown', (e) => {
        // ipc拖动到目录，按住ctrl是复制
        if(e.key === 'Control') {
          this.isControl = true
        }
      })
      // 当松开ctrl键的时候，鼠标经过的文字的移动到
      document.addEventListener('keyup', (e) => {
        // ipc拖动到目录，按住ctrl是复制
        if(e.key === 'Control') {
          this.isControl = false
        }
      })
    },
    handleNodeClick(data, type) {
      // 选中path 完整目录名
      this.selectPath = data.path
      // 选中id
      if (data.hasOwnProperty("id")) {
        this.selectedNode = data.id;
      } else {
        this.selectedNode = data.uuid;
      }
      this.$store.commit('setSelectCatalog', {
          id: this.selectedNode, 
          path: this.selectPath,
          data: data
        }
      )
      // data.showChildren = !data.showChildren;
      // data.situation = this.situation;

      // 折叠与类型
      // this.$set(data, "loading", true);
      this.$set(data, "showChildren", !data.showChildren);
      this.$set(data, "situation", this.situation);
      if (!data.ip) {
        this.recursionVisible(data, data.showChildren)
      }
      this.updateView() // 更新视图
      if (data.ip) {
          if (this.situation === "recordMgt") {
            this.$emit('showDataBase', data) // 热力图展示
            this.$emit('changeSelectIp', data.ip) // 选中的ip，给到热力图和数据图
          } else if (this.situation === "live") {
            this.$emit('selectIpc', 'ipc', data) // 点击ipc组织树
          } else if (this.situation === "record") {
            console.log("record");
            this.$emit('selectIpc', data) // 点击ipc组织树
            if (type === 'icon') {
              // 录像页面，点击左侧小图标
              bus.$emit('showComplete', data);
            }
          }
      } else {
        if (this.situation === "catalog") {
          console.log("catalog");
          this.$emit("updateIpcList", data);
          // if (data.showChildren) { // 折叠时不获取
          // }
        } else if (this.situation === "ipcMgt") {
          console.log("ipcMgt");
          this.$emit("updateIpcList", data);
        } else if (this.situation === "recordMgt") {
          console.log("recordMgt");
        } else if (this.situation === "live") {
          console.log("live");
          if (data.path === this.$t('ipcList.rootCompare')) {
            this.$emit('selectIpc', 'catalog', data, this.ipcList) // 点击ipc组织树
          } else {
            this.$emit('selectIpc', 'catalog', data) // 点击ipc组织树
          }
        } else if (this.situation === "record") {
          console.log("record");
        }
      }
    },
    // 递归遍历zi'jie'dian
    recursionVisible (data, status) {
      if (status) {
        // 打开,只打开子节点下面第一层
        data.children.forEach(node => {
          node.visible = status
          // 执行下面的就是把所有的children都展开了，应该只操作一层
          // if (node.children) {
          //   this.recursionVisible(node.children, status)
          // }
        })
        if (this.situation !== 'catalog' && this.situation !== 'ipcMgt') {
          data.ipc_list && data.ipc_list.length > 0 && data.ipc_list.forEach(ipc => {
            ipc.visible = status
          })
        }
      } else {
        // 关闭, 必须都要关闭
        data.children.forEach(node => {
          node.visible = status
          node.showChildren = status // 展开节点都给它收起来
          if (node.children) {
            this.recursionVisible(node, status)
          }
        })
        if (this.situation !== 'catalog' && this.situation !== 'ipcMgt') {
          data.ipc_list && data.ipc_list.length > 0 && data.ipc_list.forEach(ipc => {
            ipc.visible = status
          })
        }
      }
    },
    // 被拖拽对象
    startDrag($event, item) {
      this.$store.commit("setDragObj", item); // 记录拖动对象
    },
    // 经过，$event是目标对象
    onDragOver ($event, item) {
      if (item.path === this.$t('ipcList.default catalog')) {
        // ipc拖动到默认目录/ 其它目录拖动到默认目录
        $event.dataTransfer.dropEffect = 'none'
      }
      if (this.$store.state.dragObj && !this.$store.state.dragObj.path && item.path === this.$t('ipcList.rootCompare')) {
        // ipc拖动到根目录
        $event.dataTransfer.dropEffect = 'none'
      }
      // document.addEventListener('wheel', function(e) {
      //   e.preventDefault()
      // }, { passive: false });
    },
    onDragEnter ($event) {
      document.addEventListener('wheel', function(e) {
        e.preventDefault()
      }, { passive: false });
    },
    // 被覆盖的对象，拖动时松开
    onDrop($event, target, uuid) {
      try {
        if (uuid) {
            /* 情况1：表格拖动到目录松开执行 */
            // 排除1：表格ipc不能拖动到根目录或者默认目录
            if (target === this.$t('ipcList.default catalog') || target === this.$t('ipcList.rootCompare')) {
              this.$message({
                type: 'error',
                message: this.$t('ipcList.target catalog cannot be root')
              })
              return
            }
            if (target === this.$store.state.selectCatalog.path) {
              // 移动到自己身上不触发
              return
            }
            // 拖动的uuid列表
            // let uuidList
            // // 直接拖，没有点击，draggedData-是uuid字符串，非json
            // if (!this.isJsonString(draggedData)) {
            //   uuidList = [draggedData]
            // } else if (Array.isArray(JSON.parse(draggedData))) {
            //   // 点击后再拖动，拖1个或者多个，是json数据
            //   uuidList = JSON.parse(draggedData).map(item => item.uuid)
            // }
            if (this.isControl && this.$store.state.selectCatalog.path !== this.$t('ipcList.default catalog')) {
              this.addCfgCataLogIpc(target, uuid.map(item => item.uuid))
            } else {
              // target新目录名 this.selectPath旧目录名
              this.modifyIpcCatalog(target, this.$store.state.selectCatalog.path, uuid.map(item => item.uuid))
            }
        } else {
          /* 情况2：目录拖动目录执行 */
          let { element, parent } = this.getChildAndParentTree(this.treeObj.children, target.getAttribute('attrs-path'))
          let item = element
          // 获取拖拽对象在列表中的索引
          let dragObj = this.$store.getters.dragObj;
          // step0.1: 禁止拖拽到自己本身和存在拖拽到指定目录下
          if (item && dragObj && dragObj.path !== item.path) {
            // 对拖拽的对象进行处理 parent->拖拽对象旧的父亲
            let { element, parent } = this.getChildAndParentTree(
              this.treeObj.children,
              dragObj.path
            );
            // step0.2: 拖拽到自己的父亲下面不做操作 通过path，唯一性
            let flag = item.children.find(item => item.path === dragObj.path)
            if (flag) {
              return
            }
            // step0.3：拖拽到目标目录下有重名的提示 通过name，指定目录下不存在即可
            let repeat = item.children.find(item => item.name === dragObj.name)
            if (repeat) {
              this.$message({
                type: 'error',
                message: this.$t('ipcList.the target catalog has repeated name')
              })
              return
            }
            // step0.4：不允许拖动到默认目录
            if (item.name === this.$t('ipcList.default catalog compare')) {
              this.$message({
                type: 'error',
                message: this.$t('ipcList.target catalog cannot be default target')
              })
              return
            }
            
            let arr = dragObj.path.split('/')
            let old_name = dragObj.path
            let newName = item.path === this.$t('ipcList.rootCompare') ? '/' + arr.slice(-1) : item.path + '/' + arr.slice(-1) // 目标是根目录，不带前缀
            let nameParams = {
              old_name: dragObj.path, 
              new_name: newName
            }
            modCfgCataLog(nameParams).then(res => {
              // step1: 删除自己本身, 获取拖拽对象在列表中的索引
              let dragIndex = parent.children.indexOf(dragObj);
              // 从列表中移除拖拽对象
              parent.children.splice(dragIndex, 1);

              // step2: 将拖拽对象添加到目标节点的子节点中
              // 修改拖拽对象的path(包括name和children里面的name值)
              // item.children.push(dragObj);
              insertSorted(item.children, dragObj)

              // step3: 移动目录接口
              this.$message({
                type: 'success',
                message: this.$t('ipcList.modify success')
              })
              // step4: 修改该目录下所有节点的path值，name不用变,item.path-新的要替换的；parent旧的要替换的
              let newParentName = item.path === this.$t('ipcList.rootCompare') ? '' : item.path
              let oldParentName = parent.path === this.$t('ipcList.rootCompare') ? '' : parent.path
              this.modifyParentPath(
                dragObj, 
                newParentName, 
                oldParentName,
                item.level + 1 // 目标目录的层级
              )

              // step5 上面两步修改了treeData里面的数据，此时重新拍平一下数组更新视图即可
              this.initFlatten()
              this.updateVisibleData()
              // step6 通知父组件修改对应节点
              this.$emit('moveCatalog', oldParentName, newParentName, old_name, item)
            }).catch(error => {
              console.log(error, 'err');
              if (error.response && error.response.data && error.response.data.message) {
                this.$message({
                  showClose: true,
                  message: error.response.data.message,
                  type: 'error'
                });
              }
            })
          }
        }
        // this.dragObj = undefined;
        // this.$store.commit("setDragObj", null); // 记录拖动对象
      } catch (error) {
        console.log(error, 'error');
      }
    },
    /*
      **修改移动的拖拽对象的所有后代的path
      *moveObj移动的对象
      *parentName修改的父目录的名称
      **
    */
    modifyParentPath(moveObj, newParent, oldParent, level) {
      // /a是目标目录 拖动/b/c 子目录：/b/c/d ；/b/c/d/e 
      // 把/b/c拖动到/a，直接把前面的/b都替换为/a，并且replace只会匹配一次，不用担心父子重名

      // 情况1：非根目录下的目录拖动到其它目录
      if (oldParent === '') {
        moveObj.path = newParent + moveObj.path
      } else {
        // 情况2：根目录下的目录移动到其它目录，/33 -> /22/331，此时就是/22/331/33
        moveObj.path = moveObj.path.replace(oldParent, newParent)
      }
      // 修改层级
      moveObj.level = level
      for (let i = 0; i < moveObj.children.length; i++) {
        this.modifyParentPath(moveObj.children[i], newParent, oldParent, level + 1)
      }
      return
    },
    // 判断是否是json
    isJsonString (str) {
      try {
        if (JSON.parse(str)) {
          return true;
        }
      } catch (error) {
        console.log(error, 'error');
        return false
      }
    },
    /**
     * 从A目录移动ipc到B目录
     *
     * @param {string} new_catalog - ipc所在新目录
     * @param {string} old_catalog - ipc所在旧目录
     * @param {Array} ipc_list - 移动的uuid的list
     * @returns {Object} -
     */
    modifyIpcCatalog(new_catalog, old_catalog, ipc_list) {
      return new Promise((resolve, reject) => {
        if (old_catalog === this.$t('ipcList.default catalog')) {
          old_catalog = '/'
        }
        let data = {
          new_catalog,
          old_catalog,
          ipc_list
        };
        modifyIpcCataLog(data)
          .then(response => {
            this.$message.success(response.data);
            // 通知表格更新当前选中目录下的ipc,定时器-出现过移动后获取ipc返回还是旧的情况，短做延时处理
            setTimeout(() => {
              this.$store.commit('setTableMoveFlag', true)
            }, 800);
            resolve(response);
          })
          .catch(error => {
            console.log(error);
            this.$message.error(error.response.data);
            reject(error);
          });
      });
    },
    /**
     * 从A目录复制ipc到B目录
     *
     * @param {string} name - 指定目录
     * @param {Array} ipc_list - 移动的uuid的list
     * @returns {Object} -
     */
    addCfgCataLogIpc(name, ipc_list) {
      return new Promise((resolve, reject) => {
        let data = {
          name,
          ipc_list
        };
        addCfgCataLogIpc(data)
          .then(response => {
            this.$message.success(response.data);
            resolve(response);
          })
          .catch(error => {
            console.log(error);
            this.$message.error(error.response.data);
            reject(error);
          });
      });
    },
    /**
     * 获取树结构中指定目标元素及其父元素。
     *
     * @param {Array} arr - 包含树结构的数组
     * @param {string} targetName - 目标元素的名称
     * @param {Object|null} [parent=null] - 父元素，默认为 null
     * @returns {Object} - 包含目标元素和其父元素的对象
     */
    getChildAndParentTree(arr, targetName, parent = null) {
      for (let i = 0; i < arr.length; i++) {
        let currentObj = arr[i];
        if (currentObj.path === targetName) {
          return { element: currentObj, parent };
        }
        if (currentObj.children && currentObj.children.length > 0) {
          let result = this.getChildAndParentTree(
            currentObj.children,
            targetName,
            currentObj,
          );
          if (result.element) {
            return result;
          }
        }
      }
      if (!parent) {
        return {
          element: null,
          parent: this.treeObj.children[0],
        };
      } else {
        return { element: null, parent };
      }
    },
    modifyCatalog (item) {
      this.$emit('modifyCatalog', item)
    },
    addCatalog (item) {
      this.$emit('addCatalog', item)
    },
    deleteCatalog (item) {
      this.$emit('deleteCatalog', item)
    },
    deleteCatalogSure (node) {
      let { parent, element } = this.getChildAndParentTree(this.treeObj.children, node.path)
      if (parent) {
        let son = node.children
        /* step1: 父组件的tree使用splice出现删除第一个元素;可能失效的情况，改用filter成功 */
        // let ind =  fatherNode.children.findIndex(item => item.path === data.name)
        // if (ind) fatherNode.children.splice(ind, 1)
        parent.children = parent.children.filter(item => item.path !== node.path)

        /* step2: 往parent.children里面push子子的内容，备注：删除某个节点的内容，子子节点不会一并被删除 */
        if (son && son.length > 0) {
          /* step2.1: 先改path，level，visible */
          let newParentName = parent.path === this.$t('ipcList.rootCompare') ? '' : parent.path
          let oldParentName = node.path === this.$t('ipcList.rootCompare') ? '' : node.path
          for (let i = 0; i < son.length; i++) {
            this.modifyParentPath(
              son[i], 
              newParentName, 
              oldParentName,
              parent.level + 1 // 目标目录的层级
            )
            /* step2.2 push过去 */
            insertSorted(parent.children, son[i])
          }
        }
      }
    },
    // 特殊IPC和节点模式点击
    selectIpcItem (node) {
      this.$emit("changeSelectIp", node.ip, node.uuid)
      this.$emit("showDataBase", node);
      this.$store.commit('setSelectCatalog', {data: node})
    },
    onMousedown (event, item) {
      if (this.situation !== 'catalog') {
        return
      }
      if (item.path === this.$t('ipcList.rootCompare') || item.path === this.$t('ipcList.default catalog')) {
        return
      }
      let ball = document.getElementById("drag-logo");
      ball.querySelector("span").innerText = this.catalogText + ' ' +  item.name;
      // ball.style.opacity = 1; // 在mousemove上面修改值为opacity，dom必须在这儿创建不然无法显示
      ball.style.position = 'absolute';
      ball.style.zIndex = 1000;
      this.clientX = event.clientX
      this.clientY = event.clientY
      this.moveAt(event.clientX, event.clientY);
      document.addEventListener('mousemove', this.onMouseMove);
      document.addEventListener('mouseup', this.onDocumentMouseup);
      this.$store.commit("setDragObj", item); // 记录拖动对象
      this.$emit("updateCurrentDragObj", item);
    },
    moveAt(clientX, clientY) {
      // 移动现在位于坐标 (pageX, pageY) 上的图标 ,将初始的偏移考虑在内
      let ball = document.getElementById("drag-logo");
      let ballMove = document.getElementById("hover-text")
      ball.style.left = clientX  + 15 + 'px';
      ball.style.top = clientY  + 'px';
      ballMove.style.left = clientX  - 60 + 'px';
      ballMove.style.top = clientY  + 30 + 'px';
    },
    onMouseMove(event) {
      // 计算鼠标移动的距离
      let distance = Math.sqrt(Math.pow(event.clientX - this.clientX, 2) + Math.pow(event.clientY - this.clientY, 2))
      // 鼠标移动距离超过8才执行，避免点一下就触发
      if (distance > 8) {
        this.isMouseMove = true
        let ball = document.getElementById("drag-logo");
        ball.style.opacity = 1;
        let target = document.elementFromPoint(event.clientX, event.clientY); // 鼠标松开在谁身上
        let parent = this.getElementParent(target, 'tree-item-content') // 找到所有子元素的父元素(鼠标松开到目录上的target可能不统一)
        if (parent) {
          this.moveToName = parent.querySelector('span[attrs-path]').getAttribute('attrs-path') // 通过父目录下面的指定span拿到新目录名
          let ballMove = document.getElementById("hover-text")
          ballMove.style.opacity = 1;
          this.changeMoveName()
        } else {
          let ballMove = document.getElementById("hover-text")
          ballMove.style.opacity = 0;
          ballMove.querySelector('span').innerText = ""
        }
        this.moveAt(event.clientX, event.clientY);
      }
    },
    changeMoveName () {
      if (this.moveToName === this.$t('ipcList.default catalog')) {
        this.moveText = this.$t('ipcList.can not move to')
      } else {
        // 默认目录目录下不能复制，文字提示只能为 移动到，不能为复制到
        this.moveText = this.$t('ipcList.move To')
      }
      // 目录提示
      let ballMove = document.getElementById("hover-text")
      ballMove.querySelector('span').innerText = this.moveText + this.moveToName
    },
    // 从自身节点开始往父节点上找，是否有指定parentName的dom
    getElementParent(node, parentName) {
      if (!node) {
        return null
      }
      // 自身就是目标
      if (node.className && node.className.includes(parentName)) {
        return node
      }
      let parent = node.parentNode 
      let flag = parent && parent.className && parent.className.includes(parentName)
      if (flag) {
        // 父节点是目标
        return parent
      } else {
        return this.getElementParent(node.parentNode, parentName)
      }
    },
    onDocumentMouseup(event) {
      let ball = document.getElementById("drag-logo");
      ball.style.opacity = 0;
      ball.querySelector("span").innerText = ""
      document.removeEventListener('mousemove', this.onMouseMove);
      document.removeEventListener('mouseup', this.onDocumentMouseup);
      let target = document.elementFromPoint(event.clientX, event.clientY);
      this.clientX = 0
      this.clientY = 0
      // 清除"移动到"的提示
      let ballMove = document.getElementById("hover-text")
      ballMove.style.opacity = 0;
      ballMove.querySelector('span').innerText = ""
      // 获取uuid或者id或者name
      // 更新数据 curDragObjItem 为当前正在拖动的元素
      if (this.isMouseMove) {
        this.onDrop(event, target);
        this.isMouseMove = false
      }
    },
  },
};
</script>

<style scoped lang="less">
.viewport {
  position: relative;
  height: 100%;
  overflow-y: auto;
  // margin: auto;
}
.placeholder {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  // 占位容器压在底下
  z-index: -1; 
}
.sb-tree {
  position: absolute;
  min-height: 100px;
  top: 0;
  left: 0;
  right: 0;
  list-style: none;
  li {
    white-space: nowrap;
    margin-top: 2px;
    > span {
      box-sizing: border-box;
    }
    .tree-item {
      width: 100%;
      height: 26px;
      line-height: 26px;
      display: flex;
      align-items: center;
      padding-right: 3px;
    }
    .tree-item-content {
      width: 100%;
      display: flex;
      align-items: center;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      .el-icon-caret-bottom,
      .el-icon-caret-right {
        color: #c0c4cc;
      }
    }
    span.text-hover {
      flex: 1;
      display: inline-block;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .el-dropdown {
      font-size: 18px;
      font-weight: 700;
    }
  }
}

.fileStore.ipc-item {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  margin: 10px 0 15px 11px;
  max-width: 285px;
  // height: 132px;
  &:hover {
      background: #f4f7ff;
      cursor: pointer;
  }
  & > div {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    padding: 5px 0 10px 5px;
  }
  & span {
      color: rgba(29, 33, 41, 0.6);
      font-size: 14px;
      font-weight: Regular;
  }
  & > div:first-child > span:first-child {
      color: rgba(29, 33, 41, 1);
      font-weight: Regular;
  }
  & > div > span:first-child {
      color: rgba(29, 33, 41, 1);
  }
  & > div:first-child > span:last-child {
      color: rgba(29, 33, 41, 0.6);
      font-weight: Regular;
  }
}
/deep/.el-table.ipcSpecialTable {
  .el-table__empty-text {
    width: 100%;
  }
}
</style>